<?php
declare (strict_types = 1);

namespace app\controller\backend;

use app\model\AdminMenu;
use app\model\PhoneCode;
use app\service\PhoneCodeService;
use app\service\RoleService;
use app\service\sms\ALiSms;
use app\validate\LoginValidate;
use app\model\Admin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Env;
use think\facade\Lang;
use xiaodi\JWTAuth\Facade\Jwt;

class AccountController extends \app\BaseController
{

    /**
     * @param Admin $adminModel
     * @return \think\response\Json
     * @throws \app\exception\ModelEmptyException
     * @throws \app\exception\ModelException
     */
    public function login(Admin $adminModel): \think\response\Json
    {
        if (request()->isPost()) {
            $param = request()->only(['account','password']);


            $pattern = "/^[\w\.-]+@\w+\.\w+(\.\w+)?$/";
            if(!env('APP_DEBUG') == true || !(preg_match($pattern,$param['account']) && env('APP_DEBUG') == true)){
                $param['account'] = $this->RSA_openssl($param['account'], 'decode');
                $param['password'] = $this->RSA_openssl($param['password'], 'decode');
            }

            // 检验完整性
            try {
                validate(LoginValidate::class)->scene('login')->check($param);

            } catch (ValidateException $e) {
                return jsonReturn(-1, $e->getError());
            }
            $where = ['account' => $param['account']];
            $admin = $adminModel->getAdmin($where,['role'])['data'];
            if (!checkPassword($param['password'], $admin['password'])) {
                return jsonReturn(-2, Lang::get('用户名密码不正确'));
            }
            if ($admin['status'] == 2) {
                return jsonReturn(-3, Lang::get('该账号已经被禁用'));
            }

            if ($admin['code_auth'] == 1 && !empty($admin['phone'])) {
                $data = [
                    'phone' => $admin['phone'],
                    'code' => random_code_type(6, 'number'),
                    'seller_id' => $admin['seller_id'],
                    'expired_time' => date('Y-m-d H:i:s', time() + 5 * 60), // 登录验证码5分钟有效
                ];

                //保存发送code记录
                $codeModel = new PhoneCode();
                $codeModel->insertGetId([
                    'phone' => $data['phone'],
                    'code' => $data['code'],
                    'expired_time' => $data['expired_time']
                ]);

                Cache::set($admin['phone'] . '_login', time(), 5 * 60);
                if (Env::get('APP_DEBUG')) {
                    return jsonReturn(0, 'code_auth', $data);
                }

                $res = ALiSms::sendOneAuthMsg($data);
                if ($res['code'] != 0) {
                    return json($res);
                }
                return jsonReturn(0, 'code_auth', ['phone' => $admin['phone']]);
            }

            return $this->getMenuAndToken($admin);
        }
    }

    /**
     * @throws \app\exception\ModelEmptyException
     * @throws \app\exception\ModelException
     */
    public function authCode(Admin $adminModel): \think\response\Json
    {
        $param = request()->only(['phone','code']);

        $param['phone'] = $this->RSA_openssl($param['phone'], 'decode');
        $param['code'] = $this->RSA_openssl($param['code'], 'decode');

        $authCodeRes = PhoneCodeService::authCode($param);
        if ($authCodeRes['code'] != 0) {
            return json($authCodeRes);
        }

        $where = ['phone' => $param['phone']];
        $admin = $adminModel->getAdmin($where,['role'])['data'];
        return $this->getMenuAndToken($admin);
    }

    /**
     * @throws \app\exception\TokenException
     */
    protected function getMenuAndToken($admin): \think\response\Json
    {
        // 缓存权限数据
        $roleRes = RoleService::getMenuAndUpdateAuth($admin['id']);
//        $token = Jwt::token([
//            'uid' => $admin['id'],
//            'name' => $admin['name'],
//            'seller_id' => $admin['seller_id']
//        ]);

        $loginTime = time();
        // 登录日志
        $data = [
            'seller_id' => $admin['seller_id'],
            'admin_id' => $admin['id'],
            'admin_name' => $admin['name'],
            'title' => $admin['name'].Lang('登录后台系统'),
            'ip' => request()->ip(),
            'agent' => request()->header()['user-agent'],
            'login_time' => $loginTime
        ];
        event('AdminLoginLog',$data);
        // 更新最后登录时间
        $admin->last_login_time = $loginTime;
        $admin->save();

        $menu = $roleRes['data'];
        return jsonReturn(0, Lang::get('登录成功'), [
            'token' => createUserToken([
                'uid' => $admin['id'],
                'name' => $admin['name'],
                'seller_id' => $admin['seller_id']
            ],'admin'),
            'user' => $admin,
            'menu' => $menu,
        ]);
    }

    /**
     * @description  RSA公钥加密 私钥解密
     * @param string $data 待加解密数据
     * @param string $operate 操作类型 encode:加密 decode:解密
     * @return string 返回加密内容/解密内容
     * @throws \Exception
     */
    protected function RSA_openssl(string $data, string $operate = 'encode'): string
    {
        //RSA 公钥
        $rsa_public = config('system.rsa_public_key');

        //RSA 私钥
        $rsa_private  = config('system.rsa_private_key');

        //RSA 公钥加密
        if ('encode' == $operate) {
            $public_key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($rsa_public, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
            $key = openssl_pkey_get_public($public_key);
            if (!$key) {
                throw new \Exception('公钥不可用,请联系系统维护人员');
            }
            $return_en = openssl_public_encrypt($data, $crypted, $key);
            if (!$return_en) {
                throw new \Exception('公钥加密失败,请联系系统维护人员');
            }
            return base64_encode($crypted);
        }

        //RSA 私钥解密
        if ('decode' == $operate) {
            $private_key = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($rsa_private, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
            $key = openssl_pkey_get_private($private_key);
            if (!$key) {
                throw new \Exception('私钥不可用,请联系系统维护人员');
            }
            $return_de = openssl_private_decrypt(base64_decode($data), $decrypted, $key);
            if (!$return_de) {
                throw new \Exception('私钥解密失败,请联系系统维护人员');
            }
            return $decrypted;
        }
    }
}
